package com.kfm.login.controller;

import com.kfm.login.model.KfmUser;
import com.kfm.login.model.LoginLog;
import com.kfm.login.model.request.Email;
import com.kfm.login.model.response.Result;
import com.kfm.login.model.response.UserVO;
import com.kfm.login.service.KfmUserService;
import com.kfm.login.service.LoginLogService;
import com.kfm.login.service.SendEmailService;
import com.kfm.login.service.SendMessageService;
import com.kfm.login.util.Constant;
import com.kfm.login.util.IPUtils;
import com.kfm.login.util.LoginUtils;
import com.kfm.login.util.RSAUtils;
import com.wf.captcha.utils.CaptchaUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class KfmUserController {

    @Autowired
    private KfmUserService service;

    @Autowired
    private SendMessageService sendMessageService;

    @Autowired
    private LoginLogService loginLogService;

    @Autowired
    private SendEmailService SendEmailService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Value("${login.maxLoginTime}")
    private Integer maxLoginTime;

    @PostMapping("/user/login")
    public Result login(@RequestBody Map<String, String> map, HttpServletRequest request,
                        HttpServletResponse response) {
        // 是否携带验证码
        boolean hasCaptcha = Boolean.parseBoolean(map.get("hasCaptcha"));
        String captcha = map.get("captcha");
        if (hasCaptcha && !CaptchaUtil.ver(captcha, request)) {
            CaptchaUtil.clear(request);
            return Result.failure("验证码错误");
        }
        CaptchaUtil.clear(request);
        // 按照前端携带的 uuid 查询私钥
        String uuid = map.get("uuid");
        String privateKey = redisTemplate.opsForValue().get(uuid);
        redisTemplate.delete(uuid); // 删除 redis 中存储的私钥
        String username = RSAUtils.decrypt(privateKey, map.get("username"));
        String password = RSAUtils.decrypt(privateKey, map.get("password"));
        KfmUser login = service.login(username, password);
        if (login == null) {
            return Result.failure("登录失败！");
        }
        boolean remember = Boolean.parseBoolean(map.get("remember"));
        if (remember) {
            // 将登录用户信息存储到cookie中
            String to = LoginUtils.uuid();
            // 将登录表示存储到redis，过期时间7天
            redisTemplate.opsForValue().set(Constant.LOGIN_PREFIX + to, login.getUsername(), 7, TimeUnit.DAYS);
            Cookie cookie = new Cookie("login", to);
            Cookie cookie2 = new Cookie("test", "test");
            cookie.setPath("/");
            cookie2.setPath("/");
            cookie.setMaxAge(maxLoginTime * 24 * 60 * 60);
            response.addCookie(cookie);
            response.addCookie(cookie2);
        }
        // 登录成功先获取之前登录的地点，加入一条记录到 login_log 表中 （用户id，用户ip，ip归属地）
        addLog(login.getId(), request);
        request.setAttribute("login", login.getUsername());
        return Result.success("登录成功", new UserVO(login));
    }

    @PostMapping("/login")
    public Result login2(@RequestBody Map<String, String> map, HttpServletRequest request,
                         HttpServletResponse response) {
        KfmUser login = service.login2(map.get("username"), map.get("password"));
        if (login == null) {
            return Result.failure("登录失败！");
        }
        request.setAttribute("login", login.getUsername());
        return Result.success("登录成功", new UserVO(login));
    }

    /**
     * 添加登录日志
     *
     * @param id      用户编号
     * @param request 请求信息
     */
    private void addLog(Integer id, HttpServletRequest request) {
        // 上一次登录的地址
        LoginLog lastLog = loginLogService.findByUserId(id);
        String ip = IPUtils.getIpAddress(request);
        // 目前登录的地址
        String current = IPUtils.getLocation(ip).getContent().getAddress_detail().getCity();
        if (!current.equals(lastLog.getLocation())) {
            // 发送邮件
            SendEmailService.send("", "你的账号在非常用地点登录，登陆地点：" + current + "，如果非本人操作，请修改密码！");
        }
        LoginLog log = new LoginLog();
        log.setUserId(id);
        log.setIpAddress(ip);
        log.setLocation(current);
        loginLogService.insert(log);
    }

    @GetMapping("/getPublicKey")
    public Result getPublicKey() {
        String uuid = LoginUtils.uuid();
        Map<String, String> keys = RSAUtils.getKey();
        redisTemplate.opsForValue().set(uuid, keys.get(Constant.PRIVATE_KEY), 30, TimeUnit.MINUTES);
        return Result.success("查询公钥成功", Map.of("uuid", uuid, Constant.PUBLIC_KEY, keys.get(Constant.PRIVATE_KEY)));
    }

    @GetMapping("/sendMessage")
    public Result send(String phone) {
        String code = sendMessageService.send(phone, 6);
        if (code == null) {
            return Result.failure("发送验证码失败");
        }
        // 将获取的验证码存储到redis中，过期时间 5 分钟
        redisTemplate.opsForValue().set(phone, code, 5, TimeUnit.MINUTES);
        return Result.success("发送验证码成功", null);
    }

    @PostMapping("/phoneLogin")
    public Result phoneLogin(@RequestBody Map<String, String> map) {
        String phone = map.get("phone");
        String code = map.get("code");
        String s = redisTemplate.opsForValue().get(phone);
        if (code == null || !code.equals(s)) {
            return Result.failure("手机验证码错误！");
        }
        return Result.success("登录成功", null);
    }

    @GetMapping("/remember")
    public Result remember(String token) {
        String key = Constant.LOGIN_PREFIX + token;
        String s = redisTemplate.opsForValue().get(key);
        if (s == null) {
            return Result.failure("请登录");
        } else {
            return Result.success("成功", null);
        }
    }

    @PostMapping("/user/register")
    public Result register(@RequestBody Map<String, String> map, HttpServletRequest request) {
        String password = map.get("password");
        String repass = map.get("repass");
        if (password == null || !password.equals(repass)) {
            return Result.failure("两次密码不一致");
        }
        if (!CaptchaUtil.ver(map.get("captcha"), request)) {
            CaptchaUtil.clear(request);
            return Result.failure("验证码错误");
        }
        String username = map.get("username");
        if (username == null || username.isEmpty()) {
            return Result.failure("用户名为空");
        }
        CaptchaUtil.clear(request);
        KfmUser user = new KfmUser();
        user.setUsername(username);
        user.setPassword(password);
        int insert = service.insert(user);
        return insert > 0 ? Result.success("注册成功", null) : Result.failure("注册失败");
    }

    @PostMapping("/user/registerE")
    public Result registerE(@RequestBody @Validated(Email.class) KfmUser user) {
        log.info("注册成功");
        return Result.success("注册成功", null);
    }

    @GetMapping("/checkName")
    public Result checkName(String username) {
        KfmUser byUsername = service.findByUsername(username);
        return byUsername == null ? Result.success() : Result.failure("用户名已经被注册");
    }

}
